#ifndef _MY_DATA_
#define _MY_DATA_
#include "util.hpp"
#include<cstdlib>
#include<mutex>
#include<mysql/mysql.h>

namespace aod{
#define HOST "127.0.0.1"
#define USER "root"
#define PASS ""
#define NAME "aod_system"
	static MYSQL *MysqlInit(){//数据库初始化
		MYSQL *mysql=mysql_init(NULL);
		if(mysql==NULL){
			std::cout<<"init mysql instance failed!\n";
			return NULL;
		}
		if(mysql_real_connect(mysql,HOST,USER,PASS,NAME,0,NULL,0)==0){
			std::cout<<"connect mysql server failed!\n";
			mysql_close(mysql);
			return NULL;
		}
		mysql_set_character_set(mysql,"utf8");
		return mysql;
	}
	static void MysqlDestroy(MYSQL *mysql){//数据库销毁
		if(mysql!=NULL){
			mysql_close(mysql);
		}
		return;
	}
	static bool MysqlQuery(MYSQL *mysql,const std::string &sql){//判断sql语句执行成功
		int ret=mysql_query(mysql,sql.c_str());
		if(ret!=0){
			std::cout<<sql<<std::endl;
			std::cout<<mysql_error(mysql)<<std::endl;
			return false;
		}
		return true;
	}
	class TableVideo{//数据管理类
		private:
			MYSQL *_mysql;
			std::mutex _mutex;
		public:
			TableVideo(){
				_mysql=MysqlInit();
				if(_mysql==NULL){
					exit(-1);
				}
			}
			~TableVideo(){
				MysqlDestroy(_mysql);
			}
			bool Insert(const Json::Value &video){
				//id name info video image
				std::string sql;
				sql.resize(4096+video["info"].asString().size());//防止简介过长
				#define INSERT_VIDEO "insert tb_video values(null,'%s','%s','%s','%s');"
				if(video["name"].asString().size()==0){
					std::cout<<"输入的视频名称有错";
					return false;
				}
				//要完成的细致的话需要对各个数据进行校验，因为不校验直接用就有可能出现问题
				sprintf(&sql[0],INSERT_VIDEO,video["name"].asCString(),
											video["info"].asCString(),
											video["video"].asCString(),
											video["image"].asCString());
				return MysqlQuery(_mysql,sql);
			}
			bool Update(int video_id,const Json::Value &video){
				std::string sql;
				sql.resize(4096+video["info"].asString().size());//防止简介过长
				#define UPDATE_VIDEO "update tb_video set name='%s',info='%s' where id=%d;"
				sprintf(&sql[0],UPDATE_VIDEO,video["name"].asCString(),
											video["info"].asCString(),video_id);
				return MysqlQuery(_mysql,sql);

			}
			bool Delete(int video_id){
				#define DELETE_VIDEO "delete from tb_video where id=%d;"
				char sql[1024]={0};
				sprintf(sql,DELETE_VIDEO,video_id);
				return MysqlQuery(_mysql,sql);
			}
			bool SelectAll(Json::Value *videos){
				#define SELECTALL_VIDEO "select * from tb_video;"
				_mutex.lock();//加锁--保护查询与保存结果集到本地的过程
				bool ret=MysqlQuery(_mysql,SELECTALL_VIDEO);//判断语句执行成功
				if(ret==false){
					_mutex.unlock();//解锁
					return false;
				}
				MYSQL_RES *res=mysql_store_result(_mysql);//保存结果集到本地
				if(res==NULL){
					std::cout<<"mysql store result failed!\n";
					return false;
				}
				_mutex.unlock();//解锁
				int num_rows=mysql_num_rows(res);
				for(int i=0;i<num_rows;i++){
					MYSQL_ROW row=mysql_fetch_row(res);
					Json::Value video;
					video["id"]=atoi(row[0]);//将字符串转成整形
					video["name"]=row[1];
					video["info"]=row[2];
					video["video"]=row[3];
					video["image"]=row[4];
					videos->append(video);
				}
				mysql_free_result(res);//释放结果集
				return true;
			}
			bool SelectOne(int video_id,Json::Value *video){
				#define SELECTONE_VIDEO "select * from tb_video where id=%d;"
				char sql[1024]={0};
				sprintf(sql,SELECTONE_VIDEO,video_id);
				_mutex.lock();//加锁--保护查询与保存结果集到本地的过程
				bool ret=MysqlQuery(_mysql,sql);//判断语句执行成功
				if(ret==false){
					_mutex.unlock();//解锁
					return false;
				}
				MYSQL_RES *res=mysql_store_result(_mysql);//保存结果集到本地
				if(res==NULL){
					std::cout<<"mysql store result failed!\n";
					return false;
				}
				_mutex.unlock();//解锁
				int num_rows=mysql_num_rows(res);
				if(num_rows!=1){
					std::cout<<"have no data!\n";
					mysql_free_result(res);
					return false;
				}
				MYSQL_ROW row=mysql_fetch_row(res);
				(*video)["id"]=video_id;//将字符串转成整形
				(*video)["name"]=row[1];
				(*video)["info"]=row[2];
				(*video)["video"]=row[3];
				(*video)["image"]=row[4];
				mysql_free_result(res);//释放结果集
				return true;
			}
			bool SelectLike(const std::string &key,Json::Value *videos){
			    //                                                                 "%%s%"
				#define SELECTLIKE_VIDEO "select * from tb_video where name like '%%%s%%';"
				char sql[1024]={0};
				sprintf(sql,SELECTLIKE_VIDEO,key.c_str());
				_mutex.lock();//加锁--保护查询与保存结果集到本地的过程
				bool ret=MysqlQuery(_mysql,sql);//判断语句执行成功
				if(ret==false){
					_mutex.unlock();//解锁
					return false;
				}
				MYSQL_RES *res=mysql_store_result(_mysql);//保存结果集到本地
				if(res==NULL){
					std::cout<<"mysql store result failed!\n";
					return false;
				}
				_mutex.unlock();//解锁
				int num_rows=mysql_num_rows(res);
				for(int i=0;i<num_rows;i++){
					MYSQL_ROW row=mysql_fetch_row(res);
					Json::Value video;
					video["id"]=atoi(row[0]);//将字符串转成整形
					video["name"]=row[1];
					video["info"]=row[2];
					video["video"]=row[3];
					video["image"]=row[4];
					videos->append(video);
				}
				mysql_free_result(res);//释放结果集
				return true;
			}
			bool GetUser(const std::string &username, Json::Value &user){
				char sql[1024]={0};
				sprintf(sql, "select * from tb_user where username like '%s'", username.c_str());
				std::lock_guard<std::mutex> lock(_mutex);
				bool ret = MysqlQuery(_mysql,sql);
				if(!ret) return false;
				auto res = std::unique_ptr<MYSQL_RES, void(*)(MYSQL_RES *)>{
					mysql_store_result(_mysql),
					mysql_free_result,
				};
				if(!res) return false;
				int num_rows = mysql_num_rows(res.get());
				if( num_rows != 1) return false;

				MYSQL_ROW row = mysql_fetch_row(res.get());
				user["id"] = atoi(row[0]);
				user["username"]=row[1];
				user["password"]=row[2];

				return true;
			}
			bool InsertUser(const Json::Value &user){
				char sql[1024]={0};
				sprintf(sql, "insert tb_user values(null,'%s','%s')", user["username"].asCString(), user["password"].asCString());
				std::lock_guard<std::mutex> lock(_mutex);
				return MysqlQuery(_mysql,sql);
			}
	};
}

#endif
